home *** CD-ROM | disk | FTP | other *** search
- /*
- * BlobClick() and support routines. BlobClick() is the basic blob
- * transaction handler. Other routines and variables are used
- * to modify the way BlobClick() functions.
- *
- * unglueZoom determines whether BlobClick() will zoom an outline of the
- * receptor drag region back to the donor when a donor is unglued
- * from a receptor by double-clicking.
- *
- * badDragZoom determines whether the outline of a dragged donor will
- * be zoomed back where it was dragged from if it's not dragged
- * somewhere it can be glued to.
- *
- * The permission booleans control the types of transactions that
- * BlobClick() is allowed to perform:
- *
- * ungluePerm is true if double-clicking detaches globs from receptors.
- * xferPerm is true if globs can be transferred between receptors.
- * swapPerm is true if globs can be swapped between receptors.
- * dupPerm is true if globs can be duplicated onto other receptors.
- * replacePerm is true if transfers, swaps and duplications can cause
- * a receptor's glob to be replaced by another. Note that if
- * replacePerm is false, transfers and duplications can only be made
- * to empty receptors, and swaps fail altogether.
- *
- * Swaps take precedence over duplications, and both take precedence
- * over transfers, if two or more of these flags are on. All are
- * subject to the value of the replacement flag, as noted above.
- *
- * lastWhen and lastWhere are for double-click detection.
- * If lastWhen is set to 0, the next click will not be interpreted
- * as a double-click. Since that's how it's initialized, BlobClick()
- * never mistakes the first click passed to it for a double-click.
- *
- * BlobClick() only saves the click time and location when the user
- * clicks in a receptor blob drag region and releases the mouse without
- * moving it, since that's the only time a double-click is relevant.
- *
- * bcAdvise is the BlobClick() filter function. If it's nil, BlobClick()
- * does all the work itself. If bcFilter is set to the address of
- * some function, that function is consulted in certain circumstances
- * to see whether to continue processing or not. If the filter returns
- * false, BlobClick() terminates early.
- *
- * bcResult holds the result of the last call to BlobClick(). db1,
- * db2, rb1 and rb2 are set to indicate which blobs were involved in
- * any transaction that occurs (these are known as the cast (as in
- * cast of thousands) of the transaction). The result code and the
- * cast may be obtained by the host program with the BClickResult()
- * routine, and have meanings as follows:
- *
- * Glue: db1 = donor glued, rb1 = receptor glued to, db2 = donor replaced by
- * db1 (nil if none), rb2 nil.
- * Unglue: db1 = donor unglued, rb1 = receptor unglued from, db2, rb2 nil.
- * Transfer: db1 = donor transferred, rb1 = source receptor,
- * rb2 = destination receptor, db2 = donor replaced by db1 (nil if none).
- * Duplication: same as transfer, except db1 = donor duplicated.
- * Swap: db1 = donor originally on rb1, db2 = donor originally on rb2,
- * rb1 = source receptor, rb2 = dest receptor.
- *
- * The result code and the cast are undefined if a filter function
- * causes BlobClick() to terminate early.
- *
- * srcRect and dstRect are used by BlobClick() and BadDrag to keep
- * track of how to do zoomback on bad drags.
- */
-
- # include "BlobMgr.h"
-
-
- static Boolean FindReceptor (Point thePoint, BlobSetHandle rSet, BlobHandle *r);
-
-
- static Boolean unglueZoom = true;
- static Boolean badDragZoom = true;
-
- static Boolean ungluePerm = true;
- static Boolean xferPerm = true;
- static Boolean replacePerm = true;
- static Boolean dupPerm = false;
- static Boolean swapPerm = true;
-
-
- static long lastWhen = 0L;
- static Point lastWhere;
-
- static BAdvisoryProcPtr bcAdvise = (BAdvisoryProcPtr) nil;
-
- static short bcResult;
- static BlobHandle db1;
- static BlobHandle db2;
- static BlobHandle rb1;
- static BlobHandle rb2;
-
- static Rect srcRect, dstRect;
-
-
- /*
- * Set or get the flags determining zoomback behavior on bad drags
- * and unglue transactions
- */
-
- pascal void
- SetBCZoomFlags (Boolean uGlueZoom, Boolean bDragZoom)
- {
- unglueZoom = uGlueZoom;
- badDragZoom = bDragZoom;
- }
-
-
- pascal void
- GetBCZoomFlags (Boolean *uGlueZoom, Boolean *bDragZoom)
- {
- *uGlueZoom = unglueZoom;
- *bDragZoom = badDragZoom;
- }
-
-
- /*
- * Set or get the flags determining transaction permissions
- */
-
- pascal void
- SetBCPermissions (Boolean canUnglue, Boolean canXfer, Boolean canDup,
- Boolean canSwap, Boolean canRep)
- {
- ungluePerm = canUnglue;
- xferPerm = canXfer;
- dupPerm = canDup;
- swapPerm = canSwap;
- replacePerm = canRep;
- }
-
-
- pascal void
- GetBCPermissions (Boolean *canUnglue, Boolean *canXfer, Boolean *canDup,
- Boolean *canSwap, Boolean *canRep)
- {
- *canUnglue = ungluePerm;
- *canXfer = xferPerm;
- *canDup = dupPerm;
- *canSwap = swapPerm;
- *canRep = replacePerm;
- }
-
-
- /*
- * Set or get the address of the BlobClick advisory filter routine.
- * Pass nil to SetBCFilter to turn the filter off.
- */
-
- pascal void
- SetBCAdvisory (BAdvisoryProcPtr p)
- {
- bcAdvise = p;
- }
-
-
- pascal void
- GetBCAdvisory (BAdvisoryProcPtr *p)
- {
- *p = bcAdvise;
- }
-
-
- /*
- * FindReceptor is called with the point at which the mouse was released
- * after a donor or a receptor's glob was dragged. It returns true if
- * the mouse was released in a receptor that has an undimmed drag region
- * and either (i) has no glob, or (ii) has a glob but replacement
- * permission is on. Otherwise it returns false.
- * thePoint point at which mouse released
- * rSet receptor set
- * *r return receptor hit in this
- */
-
- static Boolean
- FindReceptor (Point thePoint, BlobSetHandle rSet, BlobHandle *r)
- {
- return (FindBlob (thePoint, rSet, r)
- && GetBDrawMode (*r, inDragBlob) == normalDraw
- && (BGlob (*r) == nil || replacePerm));
- }
-
-
- /*
- * BlobClick() -- blob transaction handler
- */
-
- pascal void
- BlobClick (Point thePt, long t, BlobSetHandle dSet, BlobSetHandle rSet)
- {
- BlobHandle d, r1, r2;
- Point thePoint;
- long dragDelta;
- Boolean badDrag = true; /* assume the worst */
-
- thePoint = thePt; /* do setup: make local copy of point */
- bcResult = 0; /* and initialize status variables */
- db1 = db2 = rb1 = rb2 = nil;
-
- /*
- * Check for double-click if unglue permission is on. If so and both
- * clicks were in drag region of a non-dim receptor that has a glob
- * glued to it, unglue the glob. (Note that the hit-tests only work
- * if the blob is not dimmed - which is as things should be.)
- */
- if (ungluePerm && t - lastWhen <= GetDblTime ())
- {
- if (rSet != nil
- && FindBlob (thePoint, rSet, &r1) == inDragBlob
- && TestBlob (r1, lastWhere) == inDragBlob)
- {
- if (bcAdvise == nil || (*bcAdvise) (advUnglue, r1))
- {
- db1 = BGlob (r1);
- rb1 = r1;
- bcResult = bcUnglue;
-
- if (unglueZoom)
- ZUnglueGlob (r1);
- else
- UnglueGlob (r1);
- }
- }
- lastWhen = 0L;
- return;
- }
-
- lastWhen = 0L;
-
- /*
- * See if the mouse was clicked in a donor blob. If so, drag an
- * outline around. If the dragged outline ends up somewhere it
- * can be glued to, do so, else zoom the outline back if appropriate.
- */
-
- if (dSet != nil && FindBlob (thePoint, dSet, &d) == inDragBlob)
- {
- if (bcAdvise != nil && (*bcAdvise) (advDClick, d) == false)
- return; /* advisory says "quit" */
-
- dragDelta = DTrackBlob (d, inDragBlob, thePoint);
- if (dragDelta != badDragResult && dragDelta != 0)
- {
- thePoint.h += LoWord (dragDelta);
- thePoint.v += HiWord (dragDelta);
- srcRect = dstRect = BDragBox (d);
- OffsetRect (&dstRect, LoWord (dragDelta), HiWord (dragDelta));
- if (rSet != nil && FindReceptor (thePoint, rSet, &r1))
- {
- if (bcAdvise == nil || (*bcAdvise) (advGlue, r1))
- {
- db1 = d;
- db2 = BGlob (r1);
- rb1 = r1;
- bcResult = bcGlue;
- GlueGlob (d, r1);
- badDrag = false;
- }
- }
- if (badDrag && badDragZoom)
- BMgrZoomRect (&dstRect, &srcRect);
- }
- }
-
- /*
- * Mouse was not clicked in a donor. If it was clicked in a receptor,
- * a glob may have been dragged back to the donor, or to another
- * receptor, so get ready to process possible unglue or inter-receptor
- * transaction. Can quit early if no receptor set was given
- * (rSet = nil) or no inter-receptor or unglue transactions are allowed.
- */
- else if (rSet != nil && (ungluePerm || xferPerm || swapPerm || dupPerm))
- {
- if (FindBlob (thePoint, rSet, &r1) == inDragBlob && BGlob (r1) != nil)
- {
- if (bcAdvise != nil && (*bcAdvise) (advRClick, r1) == false)
- return; /* advisory says "quit" */
-
- /*
- * If the mouse is released without being moved, then save the click
- * info, since it might be the first click of a double-click. There's
- * no need to check any further for a possible transaction since the
- * glob wasn't dragged anywhere.
- */
- if ((dragDelta = DTrackBlob (r1, inDragBlob, thePoint)) == 0L)
- {
- lastWhen = t; /* save click info for possible */
- lastWhere = thePt; /* double-click next time */
- }
- else if (dragDelta != badDragResult)
- {
- thePoint.h += LoWord (dragDelta);
- thePoint.v += HiWord (dragDelta);
-
- /*
- * Was the glob dragged back to it's owner? If so, unglue it if
- * unglue permission is on. Can't use TestBlob, 'cause that'll
- * be false if the donor is dimmed.
- */
- d = BGlob (r1);
- if (ungluePerm && BlobActive (d)
- && (PtInRgn (thePoint, (**d).dragRgn)
- || PtInRgn (thePoint, (**d).statRgn)))
- {
- if (bcAdvise == nil || (*bcAdvise) (advUnglue, r1))
- {
- db1 = d;
- rb1 = r1;
- bcResult = bcUnglue;
- UnglueGlob (r1); /* no zooming */
- }
- return;
- }
-
- srcRect = dstRect = BDragBox (r1);
- OffsetRect (&dstRect, LoWord (dragDelta), HiWord (dragDelta));
-
- if (FindReceptor (thePoint, rSet, &r2) && r1 != r2)
- {
-
- /*
- * Now know where the glob was dragged, so possibly have some kind
- * of inter-receptor transaction. If replaces aren't allowed, then
- * don't continue unless the receptor that was dragged to has no glob.
- * Otherwise do whichever of swapping, duplicating or transferring is
- * allowed. Precedence is in that order if more than one of them is
- * allowed.
- */
- rb1 = r1; /* set cast now, but they */
- rb2 = r2; /* won't be meaningful if */
- db1 = BGlob (r1); /* no transaction is performed */
- db2 = BGlob (r2);
- if (db2 != nil && swapPerm)
- {
- if (bcAdvise == nil || (*bcAdvise) (advSwap, r2))
- {
- SwapGlob (r1, r2);
- bcResult = bcSwap;
- badDrag = false;
- }
- }
- else if (dupPerm)
- {
- if (CanGlue (db1))
- {
- if (bcAdvise == nil || (*bcAdvise) (advDup, r2))
- {
- DupGlob (r1, r2); /* duplicate blob */
- bcResult = bcDup;
- badDrag = false;
- }
- }
- }
- else if (xferPerm)
- {
- if (bcAdvise == nil || (*bcAdvise) (advXfer, r2))
- {
- TransferGlob (r1, r2); /* transfer blob */
- bcResult = bcXfer;
- badDrag = false;
- }
- }
- }
- if (badDrag && badDragZoom)
- BMgrZoomRect (&dstRect, &srcRect);
- }
- }
- }
- }
-
-
- /*
- * Result result code of last call to BlobClick.
- */
-
- pascal short
- BClickResult (void)
- {
- return (bcResult);
- }
-
-
- /*
- * Result cast of characters involved in last call to BlobClick().
- */
-
- pascal void
- BClickCast (BlobHandle *d1, BlobHandle *d2, BlobHandle *r1, BlobHandle *r2)
- {
- *d1 = db1;
- *d2 = db2;
- *r1 = rb1;
- *r2 = rb2;
- }
-